package com.duobaoyu.dby.supply.biz.service.order.impl;

import cn.hutool.core.lang.Pair;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.duobaoyu.dby.channel.adapter.enums.ChannelCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.config.GlobalErrorCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderStatusEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderTypeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.product.ProductTypeEnum;
import com.duobaoyu.dby.channel.adapter.util.ChannelCodeUtils;
import com.duobaoyu.dby.channel.boundary.bean.order.param.LogisticQueryParam;
import com.duobaoyu.dby.channel.boundary.bean.order.pojo.OrderExtendParam;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.*;
import com.duobaoyu.dby.supply.biz.client.product.bean.bo.SkuInfoCheckBO;
import com.duobaoyu.dby.supply.biz.client.product.converter.ProductConverter;
import com.duobaoyu.dby.supply.biz.client.resource.ResourceApiClient;
import com.duobaoyu.dby.supply.biz.client.resource.bean.bo.OrderRuleConfigBO;
import com.duobaoyu.dby.supply.biz.constant.OperateSourceConstants;
import com.duobaoyu.dby.supply.biz.constant.OrderOperateConstants;
import com.duobaoyu.dby.supply.biz.converter.OrderConverter;
import com.duobaoyu.dby.supply.biz.enums.OperationLogTypeEnum;
import com.duobaoyu.dby.supply.biz.enums.OrderParentTypeEnum;
import com.duobaoyu.dby.supply.biz.enums.OrderTagEnum;
import com.duobaoyu.dby.supply.biz.event.SalesVolumeStatistics;
import com.duobaoyu.dby.supply.biz.exception.SupplyChainBizException;
import com.duobaoyu.dby.supply.biz.producer.SupplyChainDelayMessageProducer;
import com.duobaoyu.dby.supply.biz.producer.SupplyChainMQProducer;
import com.duobaoyu.dby.supply.biz.service.config.OperationLogService;
import com.duobaoyu.dby.supply.biz.service.order.OrderService;
import com.duobaoyu.dby.supply.biz.strategy.AbstractSyncOrderStatusStrategy;
import com.duobaoyu.dby.supply.biz.util.IdGeneratorUtil;
import com.duobaoyu.dby.supply.biz.util.ThreadLocalUtils;
import com.duobaoyu.dby.supply.common.biz.bo.order.*;
import com.duobaoyu.dby.supply.common.biz.dto.config.OperationLogSaveDTO;
import com.duobaoyu.dby.supply.common.biz.dto.log.LogDiff;
import com.duobaoyu.dby.supply.common.biz.dto.order.OrderPageDTO;
import com.duobaoyu.dby.supply.common.biz.dto.order.OrderStatisticsAmountDTO;
import com.duobaoyu.dby.supply.common.biz.remote.dto.order.SubmitOrderDTO;
import com.duobaoyu.dby.supply.core.common.exception.CustomAssert;
import com.duobaoyu.dby.supply.core.framework.util.FrameworkUtils;
import com.duobaoyu.dby.supply.db.entity.extend.OrderProductParamExtendInfo;
import com.duobaoyu.dby.supply.db.entity.order.Order;
import com.duobaoyu.dby.supply.db.entity.order.OrderConsignee;
import com.duobaoyu.dby.supply.db.entity.order.OrderLogistics;
import com.duobaoyu.dby.supply.db.entity.order.OrderProduct;
import com.duobaoyu.dby.supply.db.repository.order.OrderConsigneeRepository;
import com.duobaoyu.dby.supply.db.repository.order.OrderLogisticsRepository;
import com.duobaoyu.dby.supply.db.repository.order.OrderProductRepository;
import com.duobaoyu.dby.supply.db.repository.order.OrderRepository;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 订单实现
 *
 * @author fengshaoyu
 * @version 1.0.0
 * @date 2023/10/7 10:43
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final OrderConverter orderConverter;
    private final OrderRepository orderRepository;
    private final ProductConverter productConverter;
    private final ResourceApiClient resourceApiClient;
    private final ApplicationContext applicationContext;
    private final OperationLogService operationLogService;
    private final ThreadPoolExecutor supplyChainThreadPool;
    private final SupplyChainMQProducer supplyChainMQProducer;
    private final OrderProductRepository orderProductRepository;
    private final OrderLogisticsRepository orderLogisticsRepository;
    private final OrderConsigneeRepository orderConsigneeRepository;
    private final SupplyChainDelayMessageProducer supplyChainDelayMessageProducer;


    @Override
    public void tradeSnCheck(String bizTradeSn, String mchId, String serverName) {
        Order order = orderRepository.getOne(Wrappers.<Order>lambdaQuery().eq(Order::getBizTradeSn, bizTradeSn)
                .eq(Order::getMchId, mchId)
                .eq(Order::getServerName, serverName));
        CustomAssert.isTrue(ObjectUtils.isEmpty(order), "交易号不可重复");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String largeOrderSave(OrderSplitBO orderSplit, SubmitOrderDTO submitOrder) {
        List<OrderProduct> orderProductList = Lists.newArrayList();
        List<Order> orderList = Lists.newArrayList();
        List<OrderConsignee> orderConsigneeList = Lists.newArrayList();
        String supplyTradeSn = IdGeneratorUtil.getSupplyTradeSn(submitOrder.getShowServerName());
        for (OrderSplitBO.OrderSplitSkuInfo orderSplitSkuInfo : orderSplit.getOrderSkuInfoList()) {
            Order order = new Order();
            order.setChannelCode(orderSplitSkuInfo.getChannelCode());

            order.setBizTradeSn(submitOrder.getBizTradeSn());
            order.setSupplyTradeSn(supplyTradeSn);
            order.setOrderSn(orderSplitSkuInfo.getOrderSn());
            order.setOrderTradeSn(orderSplitSkuInfo.getOrderTradeSn());
            order.setOrderType(orderSplitSkuInfo.getOrderType());
            order.setParentType(OrderParentTypeEnum.AFTER_SPLIT.getValue());
            order.setServerName(ThreadLocalUtils.getBizCode());
            order.setShowServerName(submitOrder.getShowServerName());
            order.setOrderTag(OrderTagEnum.LARGE_ORDER.getValue());
            order.setOrderRemark(submitOrder.getOrderRemark());
            order.setOrderStatus(OrderStatusEnum.WAIT_PAY.getValue());
            order.setMchId(submitOrder.getMchId());
            order.setUserId(submitOrder.getUserId());
            order.setStatusChangeTime(LocalDateTime.now());
            order.setRechargeAccount(orderSplitSkuInfo.getRechargeAccount());
            BigDecimal channelOrderAmount = BigDecimal.ZERO;
            BigDecimal orderAmount = BigDecimal.ZERO;
            for (OrderSplitBO.SplitSkuInfo skuInfoCheck : orderSplitSkuInfo.getSkuInfoList()) {
                for (SubmitOrderDTO.SkuInfo skuInfo : submitOrder.getSkuInfos()) {
                    if (Objects.equals(skuInfoCheck.getSkuCode(), skuInfo.getSkuCode())) {
                        channelOrderAmount = channelOrderAmount.add(BigDecimal.valueOf(skuInfo.getSkuNum()).multiply(skuInfoCheck.getPlatformPrice()));
                        orderAmount = orderAmount.add(BigDecimal.valueOf(skuInfo.getSkuNum()).multiply(skuInfoCheck.getPlatformSellPrice()));
                    }
                }
            }

            order.setChannelOrderAmount(channelOrderAmount);
            order.setOrderAmount(orderAmount);
            orderList.add(order);

            OrderConsignee orderConsignee = orderConverter.toLargeOrderConsigneeBuild(orderSplitSkuInfo, order.getOrderSn(), supplyTradeSn);
            if (ObjectUtils.isNotEmpty(orderConsignee)) {
                orderConsigneeList.add(orderConsignee);
            }

            List<OrderProduct> orderProduct = orderConverter.toLargeOrderProduct(orderSplitSkuInfo.getSkuInfoList());
            orderProduct = orderProduct.stream().peek(item -> {
                OrderProductParamExtendInfo orderProductParamExtendInfo;
                if (ObjectUtils.isNotEmpty(item.getParamExtend())) {
                    orderProductParamExtendInfo = item.getParamExtend();
                } else {
                    orderProductParamExtendInfo = new OrderProductParamExtendInfo();
                }
                OrderProductParamExtendInfo.PhoneOperator phoneOperator = new OrderProductParamExtendInfo.PhoneOperator();
                if (Objects.nonNull(item.getTemplateJson())) {
                    phoneOperator.setFlowValue(item.getTemplateJson().getFlowValue());
                    phoneOperator.setChannelProductCode(item.getTemplateJson().getChannelProductCode());
                    orderProductParamExtendInfo.setOilCardType(item.getTemplateJson().getOilCardType());
                }
                phoneOperator.setOperatorType(Objects.isNull(phoneOperator.getOperatorType()) ? (Objects.nonNull(item.getTemplateJson()) ? item.getTemplateJson().getMobileOperator() : null) : null);
                orderProductParamExtendInfo.setElectricityFees(orderConverter.toElectricityFees(submitOrder.getElectricityFeesInfo()));
                item.setParamExtend(orderProductParamExtendInfo);
                item.setOrderSn(order.getOrderSn());
                item.setPlatformAmount(BigDecimal.valueOf(item.getSkuNum()).multiply(item.getPlatformPrice()));
                item.setPlatformSellAmount(BigDecimal.valueOf(item.getSkuNum()).multiply(item.getPlatformSellPrice()));
            }).collect(Collectors.toList());
            orderProductList.addAll(orderProduct);
        }

        //需要进行扩展信息异步补充订单数据
        List<Order> orderExtendList = orderList.stream().filter(item ->
                EnumUtils.eq(OrderTypeEnum.CALL_CHARGES_ORDER, item.getOrderType()) ||
                        EnumUtils.eq(OrderTypeEnum.CALL_SLOW_ORDER, item.getOrderType()) ||
                        EnumUtils.eq(OrderTypeEnum.FLOW_CHARGES_ORDER, item.getOrderType())
        ).collect(Collectors.toList());
        supplyChainMQProducer.orderExtendSync(orderExtendList);

        // 异步计算有运费渠道的预估运费
        Set<String> freightChannelCode = Optional.ofNullable(ChannelCodeUtils.getFreightChannel()).orElse(Collections.emptyList()).stream().map(ChannelCodeEnum::getValue).collect(Collectors.toSet());
        List<String> calcFreightOrderSnList = orderList.stream().filter(item -> freightChannelCode.contains(item.getChannelCode())).map(Order::getOrderSn).collect(Collectors.toList());
        supplyChainMQProducer.sendOrderEstimateFreightCalcMessage(calcFreightOrderSnList);


        orderProductRepository.saveBatch(orderProductList);
        orderRepository.saveBatch(orderList);
        if (CollectionUtils.isNotEmpty(orderConsigneeList)) {
            orderConsigneeRepository.saveBatch(orderConsigneeList);
        }
        this.sendPaymentTimeoutCancelMessage(orderList);
        return supplyTradeSn;
    }


    @Override
    public List<OrderInfoBO> checkOrderStatus(OrderStatusCheckBO orderStatusCheck) {
        List<Order> orderList = orderRepository.list(Wrappers.lambdaQuery(Order.class)
                .eq(StringUtils.isNotBlank(orderStatusCheck.getSupplyTradeSn()), Order::getSupplyTradeSn, orderStatusCheck.getSupplyTradeSn())
                .and(CollectionUtils.isNotEmpty(orderStatusCheck.getOrderSnList()), wrapper -> wrapper.in(Order::getOrderSn, orderStatusCheck.getOrderSnList()).or().in(Order::getOrderParentSn, orderStatusCheck.getOrderSnList()))
                .eq(Order::getParentType, OrderParentTypeEnum.AFTER_SPLIT.getValue()));
        if (CollectionUtils.isEmpty(orderList)) {
            SupplyChainBizException.fail(GlobalErrorCodeEnum.NO_ORDER);
        }
        // 非整单检查传入订单号是否都存在
        boolean isMainOrderConfirm = CollectionUtils.isEmpty(orderStatusCheck.getOrderSnList());
        if (!isMainOrderConfirm) {
            if (orderStatusCheck.getOrderSnList().size() != orderList.size()) {
                List<String> existsOrderSnList = orderList.stream().map(Order::getOrderSn).collect(Collectors.toList());
                Collection<String> subtract = CollectionUtils.subtract(orderStatusCheck.getOrderSnList(), existsOrderSnList);
                SupplyChainBizException.fail(GlobalErrorCodeEnum.NO_ORDER, subtract);
            }
        }
        if (CollectionUtils.isNotEmpty(orderStatusCheck.getCheckStatusList())) {
            List<String> illegalStatusOrderSnList = orderList.stream().filter(item -> !orderStatusCheck.getCheckStatusList().contains(item.getOrderStatus()))
                    .map(Order::getOrderSn).collect(Collectors.toList());
            CustomAssert.isTrue(CollectionUtils.isEmpty(illegalStatusOrderSnList), GlobalErrorCodeEnum.ORDER_STATE_ERROR, illegalStatusOrderSnList);
        }
        return orderConverter.toOrderInfoList(orderList);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatusByOrderSnList(List<String> orderSnList, OrderStatusEnum desiredStatus, OrderStatusEnum currentStatus, String source, String description,String failReason) {
        CustomAssert.notNull(desiredStatus, "更新的订单状态不能为空");
        CustomAssert.notEmpty(orderSnList, "订单号不能为空");
        if (Objects.nonNull(currentStatus)) {
            CustomAssert.isTrue(OrderStatusEnum.isValidTransition(currentStatus, desiredStatus), String.format("不支持%s->%s的状态跃迁", currentStatus.getDescribe(), desiredStatus.getDescribe()));
            LocalDateTime now = LocalDateTime.now();
            int effectRows = orderRepository.updateOrder(Wrappers.lambdaUpdate(Order.class)
                    .set(Order::getOrderStatus, desiredStatus.getValue())
                    .set(Order::getStatusChangeTime, now)
                    .set(desiredStatus == OrderStatusEnum.RECHARGE, Order::getConfirmOrderTime, now)
					.set(StringUtils.isNotBlank(failReason),Order::getFailReason,failReason)
                    .setSql("`version` = `version` + 1")
                    .eq(Order::getOrderStatus, currentStatus.getValue())
                    .in(Order::getOrderSn, orderSnList));
            if (effectRows != orderSnList.size()) {
                log.warn("更新订单状态结果不正确.{}->{},订单号={}, 期望行数={},实际={}", currentStatus.getDescribe(), desiredStatus.getDescribe(), orderSnList, orderSnList.size(), effectRows);
                SupplyChainBizException.fail("订单更新失败,数据发生变动,请重试!");
            }
            List<LogDiff> logLogDiffList = Lists.newArrayList(new LogDiff("订单状态", currentStatus.getDescribe(), desiredStatus.getDescribe()));
            List<OperationLogSaveDTO> collect = orderSnList.stream().map(item -> OperationLogSaveDTO.builder().diffList(logLogDiffList).scene(description).logType(OperationLogTypeEnum.ORDER.getValue()).bizKey(item).source(source).build()).collect(Collectors.toList());
            operationLogService.asyncBatchSave(collect);
        } else {
            List<Order> list = orderRepository.list(Wrappers.lambdaQuery(Order.class).in(Order::getOrderSn, orderSnList));
            CustomAssert.isTrue(orderSnList.size() == list.size(), "更新订单状态失败,订单不存在");
            Map<OrderStatusEnum, List<String>> currentOrderStatusMap = list.stream().collect(Collectors.groupingBy(item -> EnumUtils.valueOf(OrderStatusEnum.class, item.getOrderStatus()), Collectors.mapping(Order::getOrderSn, Collectors.toList())));
            // 校验状态跃迁
            for (Map.Entry<OrderStatusEnum, List<String>> orderStatusEnumListEntry : currentOrderStatusMap.entrySet()) {
                CustomAssert.isTrue(OrderStatusEnum.isValidTransition(orderStatusEnumListEntry.getKey(), desiredStatus), String.format("不支持%s->%s的状态跃迁", orderStatusEnumListEntry.getKey().getDescribe(), desiredStatus.getDescribe()));
            }
            for (Map.Entry<OrderStatusEnum, List<String>> entry : currentOrderStatusMap.entrySet()) {
                LocalDateTime now = LocalDateTime.now();
                List<String> value = entry.getValue();
                int effectRows = orderRepository.updateOrder(Wrappers.lambdaUpdate(Order.class)
                        .set(Order::getOrderStatus, desiredStatus.getValue())
                        .set(Order::getStatusChangeTime, now)
                        .set(desiredStatus == OrderStatusEnum.RECHARGE, Order::getConfirmOrderTime, now)
						.set(StringUtils.isNotBlank(failReason),Order::getFailReason,failReason)
                        .setSql("`version` = `version` + 1")
                        .eq(Order::getOrderStatus, entry.getKey().getValue())
                        .in(Order::getOrderSn, value));
                if (effectRows != value.size()) {
                    log.warn("更新订单状态结果不正确.{}->{},期望行数={},实际={}", entry.getKey().getDescribe(), desiredStatus.getDescribe(), value.size(), effectRows);
                    SupplyChainBizException.fail("订单更新失败,数据发生变动,请重试!");
                }
                List<LogDiff> logLogDiffList = Lists.newArrayList(new LogDiff("订单状态", entry.getKey().getDescribe(), desiredStatus.getDescribe()));
                List<OperationLogSaveDTO> collect = orderSnList.stream().map(item -> OperationLogSaveDTO.builder().diffList(logLogDiffList).scene(description).logType(OperationLogTypeEnum.ORDER.getValue()).bizKey(item).source(source).build()).collect(Collectors.toList());
                operationLogService.asyncBatchSave(collect);
            }
        }

        if (EnumUtils.eq(currentStatus, OrderStatusEnum.CANCEL.getValue())) {
            orderSnList.forEach(supplyChainMQProducer::sendAfterStateSync);
            List<OrderProduct> orderProducts = orderProductRepository.getBaseMapper().selectList(Wrappers.<OrderProduct>lambdaQuery().in(OrderProduct::getOrderSn, orderSnList));
            //增加销量
            List<SalesVolumeStatistics.OrderSalesVolumeStatistics> orderSalesVolumeStatisticsList = orderProducts.stream().map(orderProduct -> {
                SalesVolumeStatistics.OrderSalesVolumeStatistics volumeStatistics = new SalesVolumeStatistics.OrderSalesVolumeStatistics();
                volumeStatistics.setOrderNum(CommonConstants.ZERO);
                volumeStatistics.setBackOrderNum(orderProduct.getSkuNum());
                volumeStatistics.setOrderSn(orderProduct.getOrderSn());
                volumeStatistics.setSkuCode(orderProduct.getSkuCode());
                return volumeStatistics;
            }).collect(Collectors.toList());
            applicationContext.publishEvent(new SalesVolumeStatistics(orderSalesVolumeStatisticsList));
        }
    }


    @Override
    public List<OrderBO> list(OrderQueryInBO orderQueryIn) {
        List<Order> orderList = orderRepository.list(Wrappers.lambdaQuery(Order.class)
                .in(CollectionUtils.isNotEmpty(orderQueryIn.getOrderSnList()), Order::getOrderSn, orderQueryIn.getOrderSnList())
                .in(CollectionUtils.isNotEmpty(orderQueryIn.getOrderStatusList()), Order::getOrderStatus, orderQueryIn.getOrderStatusList())
                .eq(Objects.nonNull(orderQueryIn.getParentType()), Order::getParentType, orderQueryIn.getParentType())
                .eq(StringUtils.isNotEmpty(orderQueryIn.getOrderType()), Order::getOrderType, orderQueryIn.getOrderType())
                .eq(StringUtils.isNotEmpty(orderQueryIn.getOrderTradeSn()), Order::getOrderTradeSn, orderQueryIn.getOrderTradeSn())
                .eq(StringUtils.isNotBlank(orderQueryIn.getBizTradeSn()), Order::getBizTradeSn, orderQueryIn.getBizTradeSn())
                .eq(StringUtils.isNotBlank(orderQueryIn.getSupplyTradeSn()), Order::getSupplyTradeSn, orderQueryIn.getSupplyTradeSn())
        );
        if (CollectionUtils.isEmpty(orderList)) {
            return Collections.emptyList();
        }
        Set<String> orderSnSet = orderList.stream().map(Order::getOrderSn).collect(Collectors.toSet());
        // 订单商品
        Map<String, List<OrderProduct>> orderProductMap;
        // 订单收件信息
        Map<String, OrderConsignee> orderConsigneeMap;
        // 订单物流
        Map<String, List<OrderLogistics>> orderLogisticsMap;
        if (Optional.of(orderQueryIn).map(OrderQueryInBO::getReturnProduct).orElse(Boolean.FALSE)) {
            orderProductMap = orderProductRepository.list(Wrappers.lambdaQuery(OrderProduct.class)
                            .in(OrderProduct::getOrderSn, orderSnSet)
                            .in(CollectionUtils.isNotEmpty(orderQueryIn.getSkuCodeList()), OrderProduct::getSkuCode, orderQueryIn.getSkuCodeList()))
                    .stream().collect(Collectors.groupingBy(OrderProduct::getOrderSn));
        } else {
            orderProductMap = Collections.emptyMap();
        }
        if (Optional.of(orderQueryIn).map(OrderQueryInBO::getReturnConsignee).orElse(Boolean.FALSE)) {
            orderConsigneeMap = orderConsigneeRepository.list(Wrappers.lambdaQuery(OrderConsignee.class)
                            .in(OrderConsignee::getOrderSn, orderSnSet))
                    .stream().collect(Collectors.toMap(OrderConsignee::getOrderSn, Function.identity()));
        } else {
            orderConsigneeMap = Collections.emptyMap();
        }
        if (Optional.of(orderQueryIn).map(OrderQueryInBO::getReturnLogistics).orElse(Boolean.FALSE)) {
            orderLogisticsMap = orderLogisticsRepository.list(Wrappers.lambdaQuery(OrderLogistics.class).in(OrderLogistics::getOrderSn, orderSnSet))
                    .stream().collect(Collectors.groupingBy(OrderLogistics::getOrderSn));
        } else {
            orderLogisticsMap = Collections.emptyMap();
        }
        return orderList.stream().map(item ->
                        orderConverter.toOrder(item,
                                orderProductMap.get(item.getOrderSn()),
                                orderConsigneeMap.get(item.getOrderSn()),
                                orderLogisticsMap.get(item.getOrderSn())))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submitOrderSave(OrderSubmitBO orderSubmit, SubmitOrderDTO submitOrder) {
        String supplyTradeSn = IdGeneratorUtil.getSupplyTradeSn(submitOrder.getShowServerName());
        List<Order> orderList = Lists.newArrayList();
        List<OrderProduct> orderProductList = Lists.newArrayList();
        List<OrderConsignee> orderConsigneeList = Lists.newArrayList();

        for (OrderSubmitBO.OrderInfo orderInfo : orderSubmit.getOrderInfoList()) {
            Order order = new Order();
            order.setChannelCode(orderInfo.getChannelCode());
            order.setChannelFreightAmount(orderInfo.getChannelFreightAmount());
            order.setChannelActualFreightAmount(orderInfo.getChannelFreightAmount());

            order.setOrderTag(OrderTagEnum.ORDINARY_ORDER.getValue());
            order.setOrderSn(orderInfo.getOrderSn());
            order.setOrderTradeSn(orderInfo.getOrderTradeSn());
            order.setOrderType(orderInfo.getOrderType());
            order.setChannelTradeOrderSn(orderInfo.getChannelTradeOrderSn());
            order.setBizTradeSn(submitOrder.getBizTradeSn());
            order.setOrderStatus(OrderStatusEnum.WAIT_PAY.getValue());
            order.setSupplyTradeSn(supplyTradeSn);
            order.setMchId(submitOrder.getMchId());
            order.setUserId(submitOrder.getUserId());
            order.setServerName(ThreadLocalUtils.getBizCode());
            order.setOrderRemark(submitOrder.getOrderRemark());
            order.setShowServerName(submitOrder.getShowServerName());

            order.setRechargeAccount(orderInfo.getRechargeAccount());

            OrderConsignee orderConsignee = orderConverter.orderConsigneeBuild(orderInfo, order.getOrderSn(), supplyTradeSn);
            if (ObjectUtils.isNotEmpty(orderConsignee)) {
                orderConsigneeList.add(orderConsignee);
            }

            List<OrderProduct> orderProducts = orderConverter.toOrderProduct(orderInfo.getSkuInfos());
            orderProducts = orderProducts.stream().peek(item -> {
                OrderProductParamExtendInfo paramExtend = Objects.nonNull(item.getParamExtend()) ? item.getParamExtend() : OrderProductParamExtendInfo.builder().build();
                OrderProductParamExtendInfo.PhoneOperator phoneOperator =  productConverter.toPhoneOperator(Optional.ofNullable(orderInfo.getExtendParam()).map(OrderExtendParam::getPhoneOperatorParam).orElse(null));
                if (Objects.nonNull(item.getTemplateJson())) {
                    if (Objects.isNull(phoneOperator)) {
                        phoneOperator = new OrderProductParamExtendInfo.PhoneOperator();
                    }
                    phoneOperator.setFlowValue(item.getTemplateJson().getFlowValue());
                    phoneOperator.setOperatorType(Objects.isNull(phoneOperator.getOperatorType()) ? item.getTemplateJson().getMobileOperator() : null);
                    phoneOperator.setChannelProductCode(item.getTemplateJson().getChannelProductCode());
                    paramExtend.setOilCardType(item.getTemplateJson().getOilCardType());
                }

                paramExtend.setElectricityFees(orderConverter.toElectricityFees(submitOrder.getElectricityFeesInfo()));
                paramExtend.setPhoneOperator(phoneOperator);

                item.setParamExtend(paramExtend);
                item.setOrderSn(order.getOrderSn());
                item.setPlatformAmount(BigDecimal.valueOf(item.getSkuNum()).multiply(item.getPlatformPrice()));
                item.setPlatformSellAmount(BigDecimal.valueOf(item.getSkuNum()).multiply(item.getPlatformSellPrice()));
            }).collect(Collectors.toList());

            BigDecimal channelOrderRealityAmount = orderInfo.getSkuInfos().stream().map(OrderSubmitBO.OrderInfo.SkuInfo::getChannelPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal channelOrderAmount = orderProducts.stream().map(OrderProduct::getPlatformAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal orderAmount = orderProducts.stream().map(OrderProduct::getPlatformSellAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            order.setChannelOrderAmount(channelOrderAmount);
            order.setOrderAmount(orderAmount);
            order.setChannelOrderRealityAmount(channelOrderRealityAmount);
            orderProductList.addAll(orderProducts);
            orderList.add(order);
        }
        orderRepository.saveBatch(orderList);
        orderProductRepository.saveBatch(orderProductList);
        if (CollectionUtils.isNotEmpty(orderConsigneeList)) {
            orderConsigneeRepository.saveBatch(orderConsigneeList);
        }
        this.sendPaymentTimeoutCancelMessage(orderList);
        return supplyTradeSn;
    }


    @Override
    public void syncChannelOrderInfo(String orderSn) {
        Order order = orderRepository.getOne(Wrappers.<Order>lambdaQuery().eq(Order::getOrderSn, orderSn));
        if (Objects.isNull(order)) {
            log.warn("根据订单号同步渠道订单信息结束,未查询到订单信息供应链订单号:{}", orderSn);
            return;
        }
        OrderInfoBO orderInfo = orderConverter.toOrderInfo(order);
        FrameworkUtils.strategyInstance(AbstractSyncOrderStatusStrategy.class, order.getChannelCode()).strategyHandler(orderInfo);
    }

    @Override
    public Boolean afterSaleCancelOrder(String orderSn) {
        try {
            Order order = orderRepository.getOne(Wrappers.<Order>lambdaQuery().eq(Order::getOrderSn, orderSn));
            if (ObjectUtils.isEmpty(order)) {
                return Boolean.FALSE;
            }

            boolean check = OrderStatusEnum.checkCancel(order.getOrderStatus());
            if (check) {
                orderRepository.update(Wrappers.<Order>lambdaUpdate().set(Order::getOrderStatus, OrderStatusEnum.CANCEL.getValue())
                        .eq(Order::getOrderSn, orderSn));
                List<LogDiff> logLogDiffList = Lists.newArrayList(new LogDiff("订单状态", OrderStatusEnum.getOrderSubStatusDesc(order.getOrderStatus()), OrderStatusEnum.CANCEL.getDescribe()));
                OperationLogSaveDTO operationLogSaveDTO = OperationLogSaveDTO.builder().diffList(logLogDiffList).scene(OrderOperateConstants.AFTER_SALE_CANCEL_COMPLETE).logType(OperationLogTypeEnum.ORDER.getValue())
                        .bizKey(orderSn).source(OperateSourceConstants.SYSTEM).build();
                operationLogService.asyncSave(operationLogSaveDTO);
                supplyChainMQProducer.orderAlterSend(order.getSupplyTradeSn(), order.getServerName());
            }
        } catch (Exception e) {
            log.warn("message:{},data:{}", "售后修改订单状态失败", e);
        }
        return Boolean.TRUE;
    }

    @Override
    public boolean channelConfirmCompleted(OrderInfoBO orderInfo) {
        return Objects.nonNull(orderInfo) && StringUtils.isNotBlank(orderInfo.getChannelOrderSn());
    }

    @Override
    public IPage<OrderListBO> queryOrderPage(OrderPageDTO orderPage) {
        return orderRepository.queryOrderPage(orderPage);
    }

    @Override
    public List<OrderInfoBO> listOrderInfo(OrderQueryBO orderQuery) {
        List<Order> orderList = orderRepository.list(Wrappers.lambdaQuery(Order.class).eq(Order::getDelFlag, CommonConstants.ZERO)
                .eq(Objects.nonNull(orderQuery.getParentType()), Order::getParentType, orderQuery.getParentType())
                .eq(StringUtils.isNotEmpty(orderQuery.getSupplyTradeSn()), Order::getSupplyTradeSn, orderQuery.getSupplyTradeSn())
                .in(CollectionUtils.isNotEmpty(orderQuery.getOrderSnList()), Order::getOrderSn, orderQuery.getOrderSnList()));
        return orderConverter.toOrderInfoList(orderList);
    }

    @Override
    public List<OrderExportBO> listOrderExportInfo(OrderPageDTO orderPage) {
        return orderRepository.listOrderExportInfo(orderPage);
    }

    @Override
    public int countOrderExportInfo(OrderPageDTO orderPage) {
        return orderRepository.countOrderExportInfo(orderPage);
    }

    @Override
    public boolean updateOrderByOrderSn(UpdateOrderBO updateOrder) {
        CustomAssert.hasLength(updateOrder.getOrderSn(), "供应链订单号不能为空");
        Pair<Integer, Integer> orderStatus = updateOrder.getOrderStatus();
        if (Objects.nonNull(orderStatus)) {
            OrderStatusEnum orderStatusEnum = EnumUtils.valueOf(OrderStatusEnum.class, orderStatus.getKey());
            OrderStatusEnum desiredStatus = EnumUtils.valueOf(OrderStatusEnum.class, orderStatus.getValue());
            if (Objects.nonNull(orderStatusEnum)) {
                CustomAssert.isTrue(OrderStatusEnum.isValidTransition(orderStatusEnum, desiredStatus), String.format("不支持%s->%s的状态跃迁", orderStatusEnum.getDescribe(), desiredStatus.getDescribe()));
            }
        }
        LambdaUpdateWrapper<Order> updateWrapper = Wrappers.lambdaUpdate(Order.class)
                .set(StringUtils.isNoneBlank(updateOrder.getErrorInfo()), Order::getFailReason, updateOrder.getErrorInfo())
                .set(StringUtils.isNoneBlank(updateOrder.getOrderTradeSn()), Order::getOrderTradeSn, updateOrder.getOrderTradeSn())
                .set(StringUtils.isNoneBlank(updateOrder.getCancelReason()), Order::getCancelReason, updateOrder.getCancelReason())
                .set(StringUtils.isNoneBlank(updateOrder.getOrderTag()), Order::getOrderTag, updateOrder.getOrderTag())
                .set(StringUtils.isNoneBlank(updateOrder.getChannelTradeOrderSn()), Order::getChannelTradeOrderSn, updateOrder.getChannelTradeOrderSn())
                .set(StringUtils.isNoneBlank(updateOrder.getChannelOrderSn()), Order::getChannelOrderSn, updateOrder.getChannelOrderSn())
                .set(StringUtils.isNoneBlank(updateOrder.getOperatorRemark()), Order::getOperateRemark, updateOrder.getOperatorRemark())
                .set(Objects.nonNull(updateOrder.getEstimateFreight()), Order::getChannelFreightAmount, updateOrder.getEstimateFreight())
                .set(Objects.nonNull(updateOrder.getChannelActualFreightAmount()), Order::getChannelActualFreightAmount, updateOrder.getChannelActualFreightAmount())
                .set(Objects.nonNull(orderStatus) && Objects.nonNull(orderStatus.getValue()), Order::getOrderStatus, Objects.nonNull(orderStatus) ? orderStatus.getValue() : null)
                .set(Objects.nonNull(updateOrder.getAfterSalesAllowed()), Order::getAfterSalesAllowed, updateOrder.getAfterSalesAllowed())
                .setSql("`version` = `version` + 1")
                .eq(Order::getOrderSn, updateOrder.getOrderSn())
                .eq(Objects.nonNull(orderStatus) && Objects.nonNull(orderStatus.getKey()), Order::getOrderStatus, Objects.nonNull(orderStatus) ? orderStatus.getKey() : null);
        if (updateOrder.needSaveLog()) {
            OperationLogSaveDTO operationLogSaveDTO = OperationLogSaveDTO.builder().diffList(updateOrder.getLogChangeItemList()).scene(updateOrder.getDescription()).logType(OperationLogTypeEnum.ORDER.getValue())
                    .bizKey(updateOrder.getOrderSn()).source(updateOrder.getSource()).build();
            operationLogService.asyncSave(operationLogSaveDTO);
        }
        return orderRepository.update(updateWrapper);
    }

    @Override
    public OrderBO getBaseInfoByOrderTradeSn(String orderTradeSn) {
        Order one = orderRepository.getOne(Wrappers.lambdaQuery(Order.class).eq(Order::getOrderTradeSn, orderTradeSn));
        return orderConverter.toOrder(one);
    }

    @Override
    public List<OrderAmountStatisticsBO> statisticsAmount(OrderStatisticsAmountDTO orderStatisticsAmount) {
        return orderRepository.statisticsAmount(orderStatisticsAmount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSpiltOrder(Pair<OrderBO, List<OrderBO>> splitInfo) {

        OrderBO oldOrder = splitInfo.getKey();
        List<OrderBO> newOrderList = splitInfo.getValue();
        // 新增的订单
        List<Order> addOrderList = orderConverter.toOrderList(newOrderList);
        // 新增的商品
        List<OrderProduct> addProductList = newOrderList.stream().map(OrderBO::getOrderProductList).filter(CollectionUtils::isNotEmpty)
                .map(orderConverter::toOrderProductList).flatMap(Collection::stream).collect(Collectors.toList());
        // 新增的收货地址
        List<OrderConsignee> addConsigneeList = newOrderList.stream().map(OrderBO::getOrderAddress).filter(Objects::nonNull).map(orderConverter::toOrderAddress).collect(Collectors.toList());

        // 更新原单
        orderRepository.update(Wrappers.lambdaUpdate(Order.class).set(Order::getParentType, OrderParentTypeEnum.BEFORE_SPLIT.getValue())
                .eq(Order::getOrderSn, oldOrder.getOrderSn()));

        if (CollectionUtils.isNotEmpty(addOrderList)) {
            orderRepository.saveBatch(addOrderList);
        }
        if (CollectionUtils.isNotEmpty(addProductList)) {
            orderProductRepository.saveBatch(addProductList);
        }
        if (CollectionUtils.isNotEmpty(addConsigneeList)) {
            orderConsigneeRepository.saveBatch(addConsigneeList);
        }
    }

    @Override
    public void validRechargeAccount(SubmitOrderDTO submitOrder, List<SkuInfoCheckBO.SkuInfo> skuInfoList) {
        if (ObjectUtils.isEmpty(submitOrder) || ObjectUtils.isEmpty(skuInfoList)) {
            return;
        }
        if (StringUtils.isNotBlank(submitOrder.getRechargeAccount())) {
            return;
        }
        // 校验直充商品是否有传充值账号
        List<SkuInfoCheckBO.SkuInfo> rechargeSkuList = skuInfoList.stream().filter(item -> ProductTypeEnum.getProductTypeEnum(item.getProductType()).getIfRechargeNo()).collect(Collectors.toList());
        for (SkuInfoCheckBO.SkuInfo skuInfo : rechargeSkuList) {
            for (SubmitOrderDTO.SkuInfo skuParam : submitOrder.getSkuInfos()) {
                if (Objects.equals(skuInfo.getSkuCode(), skuParam.getSkuCode())) {
                    CustomAssert.isTrue(StringUtils.isNotBlank(skuParam.getRechargeAccount()), GlobalErrorCodeEnum.ACCOUNT_ERROR);
                }
            }
        }
    }

    @Override
    public List<OrderInfoBO> noLogisticsOrders(Integer page, Integer pageSize) {
        List<Order> orderList = orderRepository.noLogisticsOrders(page, pageSize);
        if(CollectionUtils.isEmpty(orderList)){
        	return null;
		}
		return orderConverter.toOrderInfoList(orderList);
    }

	@Override
	public List<LogisticQueryParam.ExpressInfo> getExpressInfo(List<String> orderSnList) {
    	//TODO 如果后期有渠道需要查询本地物流轨迹,逻辑不兼容则修改此处(目前只有行云查询本地物流轨迹，一个商品一个物流轨迹单号)
		List<LogisticQueryParam.ExpressInfo> expressInfoList = new ArrayList<>();
		for (String orderSn:orderSnList) {
			LogisticQueryParam.ExpressInfo expressInfo = new LogisticQueryParam.ExpressInfo();
			List<OrderProduct> orderProducts = orderProductRepository.getBaseMapper().selectList(Wrappers.<OrderProduct>lambdaQuery().eq(OrderProduct::getOrderSn, orderSn));
			String channelExpressCode = orderProducts.stream().filter(item -> ObjectUtils.isNotEmpty(item.getResultExtend()))
					.filter(item -> StringUtils.isNotEmpty(item.getResultExtend().getChannelExpressCode()))
					.map(item -> item.getResultExtend().getChannelExpressCode())
					.distinct()
					.findFirst()
					.orElse(null);
			if(StringUtils.isEmpty(channelExpressCode)){
				return new ArrayList<>();
			}

			OrderConsignee orderConsignee = orderConsigneeRepository.getBaseMapper().selectOne(Wrappers.<OrderConsignee>lambdaQuery().eq(OrderConsignee::getOrderSn, orderSn));
			List<OrderLogistics> orderLogisticsList = orderLogisticsRepository.getBaseMapper().selectList(Wrappers.<OrderLogistics>lambdaQuery().eq(OrderLogistics::getOrderSn, orderSn));

			for (OrderLogistics orderLogistics:orderLogisticsList) {
				expressInfo.setDeliveryOrderSn(orderLogistics.getDeliveryOrderSn());
				expressInfo.setChannelExpressCompanyCode(channelExpressCode);
				expressInfo.setPhone(orderConsignee.getRecipientMobile());
				expressInfoList.add(expressInfo);
			}
		}
		return expressInfoList;
	}


	/**
     * 发送订单支付超时取消消息
     */
    private void sendPaymentTimeoutCancelMessage(List<Order> orderList) {
        supplyChainThreadPool.execute(() -> {
            for (Order order : orderList) {
                try {
                    long timeout;
                    if (OrderTagEnum.isLargeAmountOrder(order.getOrderTag())) {
                        timeout = TimeUnit.DAYS.toMillis(7L);
                    } else {
                        OrderRuleConfigBO orderRuleConfig = resourceApiClient.queryOrderRuleConfig(order.getChannelCode());
                        Integer orderCancelDay = Optional.ofNullable(orderRuleConfig).map(OrderRuleConfigBO::getOrderRule).map(OrderRuleConfigBO.OrderRule::getOrderCancelDay).orElse(CommonConstants.ZERO);
                        Integer orderCancelHour = Optional.ofNullable(orderRuleConfig).map(OrderRuleConfigBO::getOrderRule).map(OrderRuleConfigBO.OrderRule::getOrderCancelHour).orElse(CommonConstants.ZERO);
                        Integer orderCancelMinute = Optional.ofNullable(orderRuleConfig).map(OrderRuleConfigBO::getOrderRule).map(OrderRuleConfigBO.OrderRule::getOrderCancelMinute).orElse(CommonConstants.ZERO);
                        timeout = Duration.ofDays(orderCancelDay).toMillis() + Duration.ofHours(orderCancelHour).toMillis() + Duration.ofMinutes(orderCancelMinute).toMillis();
                    }
                    if (timeout > 0) {
                        supplyChainDelayMessageProducer.paymentTimeoutAutoCancel(order.getOrderSn(), timeout);
                        log.info("发送订单延迟取消消息完成: orderSn={},timeout={}", order.getOrderSn(), timeout);
                    } else {
                        log.warn("渠道未配置支付超时时间: {}", order.getChannelCode());
                    }
                } catch (Exception e) {
                    log.warn("发送订单延迟取消消息异常:  orderSn={}", order.getOrderSn(), e);
                }
            }
        });
    }
}
